package com.yyw.gulimall.order.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
 * @Classname MyRabbitConfig
 * @Description RabbitMQ 配置类
 * @Date 2020/12/23 15:44
 * @Created yyw
 */
@Configuration
@Slf4j
public class MyRabbitConfig {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 自定义消息转换器
     * @return
     */
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }

    /**
     * @PostConstruct 使该配置一生效就执行这个方法
     * 自定义RabbitTemplate，设置发送端的消息确认机制
     */
    @PostConstruct
    public void initRabbitTemplate() {
        // 设置消息发送到服务器（exchange）确认机制，该方法只要发送消息，每次都会被触发
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            /**
             * 配置类需要配置以下配置
             * publisher-confirms: true  # 开启消息发送确认机制，此处是开启确认消息到达服务器（exchange）中
             * @param correlationData 当前消息的唯一关联数据（id/msg等）
             * @param b     消息是否发送成功
             * @param s     如果失败了，失败的原因
             */
            @Override
            public void confirm(CorrelationData correlationData, boolean b, String s) {
                log.info("消息是否成功发送到服务器Exchange中===> {}, 唯一关联数据是===> {}, 失败的原因===> {}", b, correlationData, s );
            }
        });

        // 设置消息发送从服务端Exchange 到 队列Queue 的确认机制，该机制只有在失败的时候才会触发
        rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
            /**
             * 配置类需要配置以下配置
             * publisher-returns: true   # 开启消息发送确认机制。此处是开启确认消息从Exchange 是否到达 Queue 中
             * @param message   失败的消息主体
             * @param i         回复的状态码
             * @param s         回复的状态消息
             * @param s1        是由哪个交换机Exchange发送的
             * @param s2        路由键
             */
            @Override
            public void returnedMessage(Message message, int i, String s, String s1, String s2) {
                log.error("消息投递失败: {}, ==> 状态码: {}, ==> 状态消息: {}, ==> Exchange: {}, ==> 路由键: {}",
                        message, i, s, s1, s2);
            }
        });
    }

}
